﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Web.UI;
using System.Runtime.InteropServices;
using System.Net;
namespace Framework.Common
{
    public static class FileHelper
    {
        #region file operate

        #region 判断文件是否存在
        /// <summary>
        /// 返回文件是否存在
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <returns>是否存在</returns>
        public static bool FileExists(string filename)
        {
            return File.Exists(filename);
        }
        #endregion

        #region append
        /// <summary>
        /// 向文件附加
        /// </summary>
        /// <param name="fileFullName">文件全路径</param>
        /// <param name="obj"></param>
        public static void Append(string fileFullName, object obj)
        {
            using (StreamWriter sw = File.AppendText(fileFullName))
            {
                sw.Write(obj);
            }
        }
        #endregion

        #region 删除文件
        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="fileFullName">文件全路径</param>
        public static void DeleteFile(string fileFullName)
        {
            File.Delete(fileFullName);
        }
        #endregion

        #region 创建目录
        /// <summary>
        /// 建立文件夹
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static bool CreateDir(string name)
        {
            try
            {
                string directory = Path.GetDirectoryName(name);
                if (directory.IsBlank()) return false;
                if (Directory.Exists(directory)) return true;
                Directory.CreateDirectory(directory);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.Fatal("create directory error", ex);
                return false;
            }
        }
        #endregion

        #region 备份文件
        /// <summary>
        /// 备份文件
        /// </summary>
        /// <param name="sourceFileName">源文件名</param>
        /// <param name="destFileName">目标文件名</param>
        /// <param name="overwrite">当目标文件存在时是否覆盖</param>
        /// <returns>操作是否成功</returns>
        public static bool BackupFile(string sourceFileName, string destFileName, bool overwrite)
        {
            if (!File.Exists(sourceFileName))
                throw new FileNotFoundException(sourceFileName + "文件不存在！");

            if (!overwrite && File.Exists(destFileName))
                return false;

            try
            {
                File.Copy(sourceFileName, destFileName, true);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.Fatal("备份文件出错", ex);
                return false;
            }
        }


        /// <summary>
        /// 备份文件,当目标文件存在时覆盖
        /// </summary>
        /// <param name="sourceFileName">源文件名</param>
        /// <param name="destFileName">目标文件名</param>
        /// <returns>操作是否成功</returns>
        public static bool BackupFile(string sourceFileName, string destFileName)
        {
            return BackupFile(sourceFileName, destFileName, true);
        }
        #endregion

        #region 恢复文件
        /// <summary>
        /// 恢复文件
        /// </summary>
        /// <param name="backupFileName">备份文件名</param>
        /// <param name="targetFileName">要恢复的文件名</param>
        /// <param name="backupTargetFileName">要恢复文件再次备份的名称,如果为null,则不再备份恢复文件</param>
        /// <returns>操作是否成功</returns>
        public static bool RestoreFile(string backupFileName, string targetFileName, string backupTargetFileName)
        {
            try
            {
                if (!File.Exists(backupFileName))
                    throw new FileNotFoundException(backupFileName + "文件不存在！");

                if (backupTargetFileName != null)
                {
                    if (!File.Exists(targetFileName))
                        throw new FileNotFoundException(targetFileName + "文件不存在！无法备份此文件！");
                    File.Copy(targetFileName, backupTargetFileName, true);
                }
                File.Delete(targetFileName);
                File.Copy(backupFileName, targetFileName);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.Fatal("恢复文件出错", ex);
                return false;
            }
        }
        /// <summary>
        /// 恢复文件
        /// </summary>
        /// <param name="backupFileName"></param>
        /// <param name="targetFileName"></param>
        /// <returns></returns>
        public static bool RestoreFile(string backupFileName, string targetFileName)
        {
            return RestoreFile(backupFileName, targetFileName, null);
        }
        #endregion

        #region 获取文件扩展名
        /// <summary>
        /// 获取指定文件的扩展名
        /// </summary>
        /// <param name="fileName">指定文件名</param>
        /// <returns>扩展名</returns>
        public static string GetFileExtName(string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName) || fileName.IndexOf('.') <= 0)
                return string.Empty;

            fileName = fileName.ToLower().Trim();
            int index = fileName.LastIndexOf('.');
            return fileName.Substring(index, fileName.Length - index);
        }
        #endregion

        #endregion

        #region 文件更改监视
        /// <summary>
        /// 监视文件更改
        /// </summary>
        /// <param name="fullPath"></param>
        /// <param name="resetEvent"></param>
        public static void WatchFile(string fullPath, FileSystemEventHandler resetEvent)
        {
            var watcher = new FileSystemWatcher();
            string[] dirAndPath = PathHelper.GetDirPathAndFileName(fullPath);
            watcher.Path = dirAndPath[0];
            watcher.Filter = dirAndPath[1];

            watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.Size;

            watcher.Changed += resetEvent;
            watcher.Created += resetEvent;
            watcher.Deleted += resetEvent;

            watcher.EnableRaisingEvents = true;
        }
        #endregion

        #region 以指定的ContentType输出指定文件文件
        /// <summary>
        /// 以指定的ContentType输出指定文件文件
        /// </summary>
        /// <param name="filepath">文件路径</param>
        /// <param name="filename">输出的文件名</param>
        /// <param name="filetype">将文件输出时设置的ContentType</param>
        public static void ResponseFile(string filepath, string filename, string filetype)
        {
            Stream iStream = null;

            // 缓冲区为10k
            var buffer = new Byte[10000];
            // 文件长度
            // 需要读的数据长度

            try
            {
                // 打开文件
                iStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                // 需要读的数据长度
                long dataToRead = iStream.Length;

                HttpContext.Current.Response.ContentType = filetype;
                if (HttpContext.Current.Request.ServerVariables["HTTP_USER_AGENT"].IndexOf("MSIE") > -1)
                    HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + filename.Trim().UrlEncode().Replace('+', ' '));
                else
                    HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + filename.Trim());

                while (dataToRead > 0)
                {
                    // 检查客户端是否还处于连接状态
                    if (HttpContext.Current.Response.IsClientConnected)
                    {
                        int length = iStream.Read(buffer, 0, 10000);
                        HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
                        HttpContext.Current.Response.Flush();
                        buffer = new Byte[10000];
                        dataToRead = dataToRead - length;
                    }
                    else
                    {
                        // 如果不再连接则跳出死循环
                        dataToRead = -1;
                    }
                }
            }
            catch (Exception ex)
            {
                HttpContext.Current.Response.Write("Error : " + ex.Message);
            }
            finally
            {
                if (iStream != null)
                {
                    // 关闭文件
                    iStream.Close();
                }
            }
            HttpContext.Current.Response.End();
        }
        #endregion

        /// <summary>
        /// 返回指定目录下的非 UTF8 字符集文件
        /// </summary>
        /// <param name="Path">路径</param>
        /// <returns>文件名的字符串数组</returns>
        public static IEnumerable<string> FindNoUTF8File(string Path)
        {
            var folder = new DirectoryInfo(Path);
            var subFiles = folder.GetFiles();

            foreach (FileInfo file in subFiles)
            {
                if (file.Extension.ToLower().Equals(".htm"))
                {
                    bool isUtf8;
                    using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
                    {
                        isUtf8 = IsUTF8(fs);
                    }
                    if (!isUtf8)
                    {
                        yield return file.FullName;
                    }
                }
            }
        }
        ///<summary>
        /// 0000 0000-0000 007F - 0xxxxxxx  (ascii converts to 1 octet!)
        /// 0000 0080-0000 07FF - 110xxxxx 10xxxxxx    ( 2 octet format)
        /// 0000 0800-0000 FFFF - 1110xxxx 10xxxxxx 10xxxxxx (3 octet format)
        /// 
        /// 判断文件流是否为UTF8字符集
        /// </summary>
        /// <param name="sbInputStream">文件流</param>
        /// <returns>判断结果</returns>
        private static bool IsUTF8(FileStream sbInputStream)
        {
            int i;
            byte cOctets;  // octets to go in this UTF-8 encoded character 
            byte chr;
            bool bAllAscii = true;
            long iLen = sbInputStream.Length;

            cOctets = 0;
            for (i = 0; i < iLen; i++)
            {
                chr = (byte)sbInputStream.ReadByte();

                if ((chr & 0x80) != 0) bAllAscii = false;

                if (cOctets == 0)
                {
                    if (chr >= 0x80)
                    {
                        do
                        {
                            chr <<= 1;
                            cOctets++;
                        }
                        while ((chr & 0x80) != 0);

                        cOctets--;
                        if (cOctets == 0)
                            return false;
                    }
                }
                else
                {
                    if ((chr & 0xC0) != 0x80)
                        return false;

                    cOctets--;
                }
            }

            if (cOctets > 0)
                return false;

            if (bAllAscii)
                return false;

            return true;
        }

        #region 清除缓存,重启站点
        /// <summary>
        /// hack tip:通过更新web.config文件方式来重启IIS进程池（注：iis中web园数量须大于1,且为非虚拟主机用户才可调用该方法）
        /// </summary>
        public static void RestartIISProcess()
        {
            try
            {
                var xmldoc = new System.Xml.XmlDocument();
                string path = PathHelper.MapPath("~/web.config");
                xmldoc.Load(path);
                using (System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(path, null))
                {
                    writer.Formatting = System.Xml.Formatting.Indented;
                    xmldoc.WriteTo(writer);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error("RestartIISProcess", ex);
            }
        }
        #endregion
    }
}
